{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ch19. 趣味编程"
   ]
  },
  {
   "source": [
    "## 19.1 兴趣\n",
    "\n",
    "编程使人快乐，就会更加努力学习。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 19.2 柔术\n",
    "\n",
    "-   原型设计：快速地编写程序，深入地解决问题\n",
    "-   配置：快速地修改程序\n",
    "-   自动化测试：正确地修改程序"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 19.3 原型设计\n",
    "\n",
    "在实际开发工具中，完全可以先开发原型，再通过重构来获得最终的系统。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 19.4 配置\n",
    "\n",
    "提高程序抽象程度的方式：提取代码中的符号常量(symbolic constant)"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 19.4.1 提取常量 \n",
    "\n",
    "常量：指的是内置的字面量值，例如：数、字符串、列表。对于这些值，可以将其存储在全局变量中，而不在程序中反复输入它们。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 19.4.2 配置文件\n",
    "\n",
    "\n",
    "配置的级别：\n",
    "-   配置文件：使用 configparser 管理配置文件。\n",
    "-   环境变量：使用字典 os.environ 管理环境变量\n",
    "-   在命令行中向程序传递的开关和参数：使用 sys.argv 管理命令行参数；使用 argparse 管理开关(选项)"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 写入配置文件\n",
    "from configparser import ConfigParser\n",
    "config = ConfigParser()\n",
    "config[\"DEFAULT\"] = {\n",
    "        'ServerAliveInterval': '45',\n",
    "        'Compression': 'yes',\n",
    "        'CompressionLevel': '9',\n",
    "        'ForwardX11': 'yes'\n",
    "}  # 类似于操作字典的形式\n",
    "\n",
    "config['bitbucket.org'] = {'User': 'Atlan'}  # 类似于操作字典的形式\n",
    "\n",
    "config['topsecret.server.com'] = {'Host Port': '50022', 'ForwardX11': 'no'}\n",
    "\n",
    "with open('example.ini', 'w') as configfile:\n",
    "    config.write(configfile)  # 将对象写入文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "PI= 3.1415926535897931\n",
      "Welcome to the area calculation program!\n",
      "The area is 28.274333882308138\n"
     ]
    }
   ],
   "source": [
    "# 读取配置文件\n",
    "from configparser import ConfigParser\n",
    "config = ConfigParser()\n",
    "CONFIGFILE = \"area.ini\"\n",
    "config.read(CONFIGFILE)\n",
    "print(\"PI=\", config['numbers'].get('pi'))\n",
    "print(config['messages'].get('greeting'))\n",
    "radius = float(input(config['messages'].get('question') + ' '))\n",
    "print(config['messages'].get('result_message'), end=' ')\n",
    "print(config['numbers'].getfloat('pi') * radius ** 2)"
   ]
  },
  {
   "source": [
    "## 19.5 日志\n",
    "\n",
    "日志的功能：\n",
    "-   记录不同类型的条目(INFO、DEBUG、WARN、DEFINE等等)。默认情况下，只记录「WARN」\n",
    "-   只记录与程序特定部分相关的条目\n",
    "-   记录有关时间、日期等方面的信息\n",
    "-   记录到其他位置，例如：套接字\n",
    "-   配置日志器，将一些或者大部分日志过滤掉，无需重写程序就能够获得所需要的日志信息。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "# 日志处理\n",
    "import logging\n",
    "\n",
    "logging.basicConfig(level=logging.INFO, filename='mylog.log')\n",
    "logging.info('Starting program')\n",
    "logging.info('Trying to divide 1 by 0')\n",
    "print(1/0)\n",
    "logging.info(\"The division succeeded\")\n",
    "logging.info(\"Ending program\")"
   ],
   "cell_type": "code",
   "metadata": {},
   "execution_count": 4,
   "outputs": [
    {
     "output_type": "error",
     "ename": "ZeroDivisionError",
     "evalue": "division by zero",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mZeroDivisionError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-4-5e1951c2d5bc>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[0mlogging\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Starting program'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[0mlogging\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Trying to divide 1 by 0'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      8\u001b[0m \u001b[0mlogging\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"The division succeeded\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[0mlogging\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Ending program\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero"
     ]
    }
   ]
  },
  {
   "source": [
    "## 19.7 深入学习\n",
    "\n",
    "-   Andrew Hunt, David Thomas,《程序员修炼之道》\n",
    "-   Martin Fowler,《重构》\n",
    "-   Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides,《设计模式》\n",
    "-   Kent Beck,《测试驱动开发》\n",
    "-   Eric S. Raymond,《UNIX 编程艺术》\n",
    "-   Thomas H. Cormen,《算法导论》\n",
    "-   Donald E. Knuth,《计算机程序设计艺术》(卷1~卷3)\n",
    "-   Peter Van Roy Seif Haridi,《Concepts, Techniques, and Models of Computer Programming》"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 19.8 小结\n",
    "\n",
    "-   灵活性：设计和编程时，应该以灵活性为目标。\n",
    "-   原型设计：深入了解问题和可能的实现方案，编写程序的简化版本，不断完善和重构获得更好的解决方案\n",
    "-   配置：通过提取程序中的常量，使得修改程序更加容易。通过将常量放在配置文件中，使得用户能够配置程序。通过使用环境变量和命令行选项，可以进一步提高程序的可配置性。\n",
    "-   日志：有助于找出程序存在的问题或者监视程序运行的状态。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "3.6.12-final"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "source": [],
    "metadata": {
     "collapsed": false
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}